#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <time.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sqlite3.h>
#include <errno.h>
#include <sys/epoll.h>

typedef struct sockaddr * (SA);
typedef enum {TYPE_HTML,TYPE_JPG,TYPE_PNG}FILE_TYPE;

int send_head(int conn,char* filename,FILE_TYPE type)
{
	char buf[128]={0};
	char *http_cmd[6]={NULL};
	struct stat st;
	int ret = stat(filename,&st);
	if(0!=ret)
	{
		perror("stat");
		return 1;
	}
	http_cmd[0]="HTTP/1.1 200 OK\r\n";
	http_cmd[1]="Server: PT SERVER\r\n";
	http_cmd[2]="Date: Wed, 21 Jul 2021 01:09:18 GMT\r\n";
	switch(type)
	{
		case(TYPE_HTML):
			http_cmd[3]="Content-Type: text/html; charset=UTF-8\r\n";
			break;
		case(TYPE_JPG):
			http_cmd[3]="Content-Type: image/jpeg\r\n";
			break;
		case(TYPE_PNG):
			http_cmd[3]="Content-Type: image/png\r\n";
			break;
	}
	http_cmd[4]=buf;
	sprintf(buf,"content-length: %ld\r\n",st.st_size);
	http_cmd[5]="Connection: keep-close\r\n\r\n";
	int i = 0 ;
	for(i = 0 ;i<6;i++)
	{
		send(conn,http_cmd[i],strlen(http_cmd[i]),0);
	}
	return 0;
}

int send_file(int conn,char* filename,FILE_TYPE type)
{
	int ret = send_head(conn,filename,type);
	if(0 != ret)
	{
		return 1;
	}
	int fd = open(filename,O_RDONLY);
	if(-1 == fd)
	{
		perror("open");
		return 1;
	}
	while(1)
	{
		char buf[1024]={0};
		int rd_num = read(fd,buf,sizeof(buf));
		if(rd_num<=0)
		{
			break;
		}
		send(conn,buf,rd_num,0);
	}
	close(fd);

}

unsigned char FromHex(unsigned char x)
{
	if(0 == x ) 
	{
		return -1;
	}
	unsigned char y;
	if(x >= 'A' && x <= 'Z')
	{
		y = x - 'A' + 10;
	}
	else if(x >= 'a' && x <= 'z') 
	{
		y = x - 'a' + 10;
	}
	else if(x >= '0' && x <= '9') 
	{
		y = x - '0';
	}
	return y;
}

int  urlDecode(char* dest, const char* src)
{
	if(NULL == src || NULL == dest)
	{
		return -1;

	}
	int len = strlen(src);
	int i = 0;
	for(i = 0 ;i < len;i++)
	{
		if('+' == src[i])
		{
			strcat(dest,"");
		}
		else if('%' == src[i])
		{
			unsigned char high = FromHex((unsigned char)src[++i]);
			unsigned char low  = FromHex((unsigned char)src[++i]);
			unsigned char temp = high * 16 + low;
			char temp2[5] = {0};
			sprintf(temp2,"%c",temp);
			strcat(dest,temp2);
		}
	}
	return 0;
}

int check(void *arg,int col,char **result,char **title)
{
	*(int *)arg = 1;
	return 0;
}

int check_find(void *arg,int col,char **result,char **title)
{
	int fd = open("./12find_suc.html",O_RDONLY);
	if(-1 == fd)
	{
		return 1;
	}
	char *buf = malloc(1024*1024);
	read(fd,buf,1024*1024);
	close(fd);
	fd = open("./12find_suc.html",O_WRONLY|O_TRUNC);
	char *temp=NULL;
	if(*(int*)arg == 0)
	{
		temp = strstr(buf,"<body background = '04.png'>");
		temp += 29;
		buf[temp - buf] = '\0';
	}
	else
	{
		temp = strstr(buf,"<h2 align = right>");
		buf[temp - buf] = '\0';
	}
	sprintf(buf,"%s<a href = \"13goods_desc%d.html\"><img src = \"%s\"></a><br><a href = \"13goods_desc.html\">  &ensp;&ensp;%s</a><br><h2 align = right><form action = \"return\"><input type = 'submit' value = '返回'></form></h2></body></html>",buf,*(int*)arg,result[20],result[3]);
	write(fd,buf,strlen(buf));
	close(fd);

	char html[30] = {0};
	sprintf(html,"13goods_desc%d.html",*(int*)arg);
	fd = open(html,O_CREAT|O_WRONLY|O_TRUNC);
	if(-1 == fd && errno != EEXIST)
	{
		return 1;
	}
	bzero(buf,1024*1024);
	char com[128] = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>info</title></head><body bgcolor = \"#00FFFF\">";
	sprintf(buf,"%s<h6 align = center><img src=\"%s\" alt=\"%s\" width=\"50%%\" height=\"500\"></h6><h2>%s<br>市场价:%s￥<br>商城价:%s￥<br>存货:%s</h2><br>%s<br><form action = \"back\"><h2 align = right><input type = 'submit' value = '返回'></form></h2></body></html>",com,result[21],result[3],result[16],result[10],result[11],result[8],result[18]);
	write(fd,buf,strlen(buf));
	close(fd);
	*(int *)arg+=1;
	free(buf);
	return 0;
}


int url_jump(int conn,char *url)
{
	//解析帐号+密码
	char *name = NULL;
	char *passwd = NULL;
	name = strstr(url,"name");
	passwd = strstr(name,"passwd");
	name += 5;
	passwd += 7;
	char *p = index(name,'&');
	*p = '\0';
	//查询数据库
	sqlite3 *db = NULL;
	char *msg = NULL;
	int ret = sqlite3_open("./user.db",&db);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		send_file(conn,"./04login_err.html",TYPE_HTML);
		return 1;
	}
	char sqlite3_cmd[100] = {0};
	sprintf(sqlite3_cmd,"select * from user where user = '%s' and passwd = %s;",name,passwd);
	int flag = 0;
	ret = sqlite3_exec(db,sqlite3_cmd,check,&flag,&msg);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		sqlite3_free(msg);
		send_file(conn,"./04login_err.html",TYPE_HTML);
		return 1;
	}
	if(flag == 0)
	{
		send_file(conn,"./04login_err.html",TYPE_HTML);
	}
	else
	{
		send_file(conn,"./10login_suc.html",TYPE_HTML);        //查询界面
	}
	return 0;
}

int url_enroll(int conn,char *url)
{
	//解析帐号+密码
	char *name = NULL;
	char *passwd = NULL;
	char *passwdagain = NULL;
	name = strstr(url,"name");
	passwd = strstr(name,"passwd");
	passwdagain = strstr(passwd,"passwdagain");
	name += 5;
	passwd += 7;
	passwdagain += 12;
	char *p = index(name,'&');
	*p = '\0';
	p = index(passwd,'&');
	*p = '\0';
	if(strcmp(passwd,passwdagain) != 0)
	{
		send_file(conn,"./08enroll_err.html",TYPE_HTML);
	}
	//查询数据库
	sqlite3 *db = NULL;
	char *msg = NULL;
	int ret = sqlite3_open("./user.db",&db);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		send_file(conn,"./09enroll_fail.html",TYPE_HTML);
		return 1;
	}
	char sqlite3_cmd[100] = {0};
	sprintf(sqlite3_cmd,"select * from user where user = '%s';",name);
	int flag = 0;
	ret = sqlite3_exec(db,sqlite3_cmd,check,&flag,&msg);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		sqlite3_free(msg);
		send_file(conn,"./09enroll_fail.html",TYPE_HTML);
		return 1;
	}
	if(flag == 0)
	{
		char id[512] = {0};
		sprintf(id,"insert into user values('%s',%s);",name,passwd);
		sqlite3_exec(db,id,NULL,NULL,&msg);
		if(ret != SQLITE_OK)
		{
			sqlite3_close(db);
			sqlite3_free(msg);
			send_file(conn,"./09enroll_fail.html",TYPE_HTML);
			return 1;
		}
		send_file(conn,"./07enroll_suc.html",TYPE_HTML);
	}
	else
	{
		send_file(conn,"./06enroll_hav.html",TYPE_HTML);
	}
	return 0;
}

int url_find(int conn,char *url)
{
	//查询内容解析
	char *find = NULL;
	find = index(url,'=');
	char buf[512] = {0};
	if(strncmp(find+1,"%",1) == 0)
	{
		urlDecode(buf,find+1);
	}
	else
	{
		strcpy(buf,find+1);
	}
	//查询数据库
	sqlite3 *db = NULL;
	char *msg = NULL;
	int ret = sqlite3_open("./123.db",&db);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		send_file(conn,"./11find_err.html",TYPE_HTML);
		return 1;
	}
	char sqlite3_cmd[512] = {0};
	sprintf(sqlite3_cmd,"select * from goods where goods_name like '%%%s%%';",buf);
	int flag = 0;
	ret = sqlite3_exec(db,sqlite3_cmd,check_find,&flag,&msg);
	if(ret != SQLITE_OK)
	{
		sqlite3_close(db);
		sqlite3_free(msg);
		send_file(conn,"./11find_err.html",TYPE_HTML);
		return 1;
	}
	if(flag == 0)
	{
		send_file(conn,"./11find_err.html",TYPE_HTML);
	}
	else
	{    			
		send_file(conn,"./12find_suc.html",TYPE_HTML);
	}
	return 0;
}

int add_fd(int epfd,int fd)
{
	struct epoll_event event;
	event.events = EPOLLIN;
	event.data.fd = fd;
	int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
	return ret;
}

int del_fd(int epfd,int fd)
{
	struct epoll_event event;
	event.events = EPOLLIN;
	event.data.fd = fd;
	int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&event);
	return ret;
}

int main(int argc, const char *argv[])
{
	int listfd = socket(AF_INET, SOCK_STREAM,0);
	if(-1 == listfd)
	{
		perror("socket");
		exit(1);
	}
	struct sockaddr_in ser,cli;
	bzero(&ser,sizeof(ser));
	bzero(&cli,sizeof(cli));
	ser.sin_family = AF_INET;
	ser.sin_port = htons(80);
	ser.sin_addr.s_addr = INADDR_ANY;
	int ret = bind(listfd,(SA)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("bind");
		exit(1);
	}
	listen(listfd,3);
	int len = sizeof(cli);

	int epfd = epoll_create(10);
	if(epfd == -1)
	{
		perror("epoll_create");
		exit(1);
	}
	add_fd(epfd,listfd);
	struct epoll_event rev[10];
	int i = 0;
	while(1)
	{
		int ep_ret = epoll_wait(epfd,rev,10,-1);
		for(i = 0;i < ep_ret;++i)
		{
			if(rev[i].data.fd == listfd)
			{
				int conn = accept(listfd,(SA)&cli,&len);
				if(-1 == conn)
				{
					perror("accept");
					continue;
				}
				add_fd(epfd,conn);
			}
			if(rev[i].data.fd != listfd)
			{
				int conn = rev[i].data.fd;
				char buf[1024]={0};
				int rd_ret = recv(conn,buf,sizeof(buf),0);
				if(rd_ret<=0)
				{
					del_fd(epfd,conn);
					close(conn);
					continue;
				}
				printf("%s\n",buf);
				char *method = NULL;
				char* url = NULL;
				char* ver = NULL;
				method = strtok(buf," ");
				url = strtok(NULL," ");
				ver = strtok(NULL,"\r");

				if(0 == strcmp(url,"/")) //登录界面
				{
					send_file(conn,"./03login.html",TYPE_HTML);
				}
				if(0 == strcmp(url,"/favicon.ico")) //网页小图标
				{
					send_file(conn,"./01.png",TYPE_PNG);
				}
				if(0 == strncmp(url,"/login",6)) //登录
				{
					url_jump(conn,url);
				}
				if(0 == strcmp(url,"/05enroll.html")) //注册
				{
					send_file(conn,"./05enroll.html",TYPE_HTML);
				}
				if(0 == strcmp(url,"/03login.html")) //登录
				{
					send_file(conn,"./03login.html",TYPE_HTML);
				}
				if(0 == strncmp(url,"/enroll",7)) //查询注册
				{
					url_enroll(conn,url);
				}
				if(strstr(url,"png")) //传图
				{
					send_file(conn,url+1,TYPE_PNG);
				}
				if(strstr(url,"jpg"))
				{
					send_file(conn,url+1,TYPE_JPG);
				}
				if(0 == strncmp(url,"/find",5))
				{
					url_find(conn,url);
				}
				if(0 == strncmp(url,"/13goods_desc",13))
				{
					send_file(conn,url+1,TYPE_HTML);	
				}
				if(0 == strcmp(url,"/return?"))
				{
					send_file(conn,"./10login_suc.html",TYPE_HTML);	
				}
				if(0 == strcmp(url,"/back?"))
				{
					send_file(conn,"./12find_suc.html",TYPE_HTML);	
				}
				if(0 == strcmp(url,"/quit?"))
				{
					send_file(conn,"./03login.html",TYPE_HTML);
				}
			}
		}
	}
	close(listfd);
	return 0;
}

